package com.uplooking;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import com.uplooking.constant.CommConstants;
import com.uplooking.constant.TokenConstants;
import com.uplooking.pojo.UserVO;
import com.uplooking.service.impl.UserServiceImpl;
import com.uplooking.util.TokenUtils;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private UserServiceImpl userService;
	
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		//提供认证比对对象
		auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		//放行路由
		http.authorizeRequests().antMatchers("/login","/home","/regist/**","/error/**","/picture/**","/logo/**").permitAll();
		//控制路由
		http.authorizeRequests()
			.anyRequest().authenticated()
			.and()
			.formLogin().loginPage("/login")
			.usernameParameter("username")
			.passwordParameter("password")
			.successHandler(new AuthenticationSuccessHandler() {
				
				@Override
				public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
						Authentication authentication) throws IOException, ServletException {
					UserVO userVO = (UserVO) authentication.getPrincipal();
					//存储会话
					request.getSession().setAttribute(CommConstants.CommUser, userVO);
					//产生JWT
					String audience = userVO.getUsername();
					String secret = userVO.getPassword();
					String value = TokenUtils.createToken(audience, secret, TokenConstants.TokenExpire);
					//存储Cookie 
					Cookie cookie = new Cookie(TokenConstants.TokenKey, value);
					cookie.setHttpOnly(true);
					cookie.setMaxAge(TokenConstants.CookieExpire);
					cookie.setPath("/");
					response.addCookie(cookie);
					response.sendRedirect("home");
				}
			})
			.failureHandler(new AuthenticationFailureHandler() {
				
				@Override
				public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
						AuthenticationException exception) throws IOException, ServletException {
					//未审核
					if (exception instanceof DisabledException) {
						response.sendRedirect("error/disabled");					
					}
					//用户名不存在
					if (exception instanceof InternalAuthenticationServiceException) {
						response.sendRedirect("error/notfound");
					}
					//密码错误
					if (exception instanceof BadCredentialsException) {
						response.sendRedirect("error/incorrect");
					}
				}
			}).permitAll()
			.and()
			.logout().logoutSuccessHandler(new LogoutSuccessHandler() {
				@Override
				public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
						throws IOException, ServletException {
					request.getSession().invalidate();
					Cookie cookie = new Cookie(TokenConstants.TokenKey, "");
					cookie.setHttpOnly(true);
					cookie.setMaxAge(0);
					cookie.setPath("/");
					response.addCookie(cookie);
					response.sendRedirect("login");
				}
			}).permitAll()
			.and()
			.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
				
				@Override
				public void handle(HttpServletRequest request, HttpServletResponse response,
						AccessDeniedException accessDeniedException) throws IOException, ServletException {
					response.sendRedirect("error/deny");
				}
			});
		//路由安全
		http.csrf().disable();
		//框架内嵌
		http.headers().frameOptions().disable();
	}
	
	@Override
	public void configure(WebSecurity web) throws Exception {
		//过滤静态资源 -> csrf攻击
		web.ignoring().antMatchers("/html/**");
	}
}
